#include "meven.h"
#include "cJSON.h"
#include "log.h"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <time.h>
#include <unistd.h>

const char *methods[] = {"GET",     "POST",  "PUT",   "DELETE", "HEAD",
                         "OPTIONS", "PATCH", "TRACE", "CONNECT"};

string default_err_json;

void sendBadRequest(even_detail *event, http_request_t *request) {
    if (request == NULL) {
        log_info("bad request %s %s NULL request body",
                 methods[request->method], request->path.data);
    } else {
        char *message = cJSON_Print(request->body);
        log_info("bad request %s %s %s", methods[request->method],
                 request->path.data, message);
        free(message);
    }
    send(event->fd, default_err_json.data, default_err_json.len, 0);
}

void meven_add_router(meven_t *meven, const char *router,
                      httpCallback callback) {
    router_t *rout = (router_t *)malloc(sizeof(router_t));
    if (rout == NULL) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    rout->router = malloc(strlen(router) + 1);
    strncpy(rout->router, router, strlen(router) + 1);
    rout->callback = callback;
    vec_append(&meven->routers, *rout);
}

// 插入新接口
void meven_setMethod(meven_t *meven, HTTP_METHOD method, const char *path,
                     httpCallback callback) {
    method_table_t *entry = (method_table_t *)malloc(sizeof(method_table_t));
    if (entry == NULL) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    entry->key = malloc(strlen(methods[method]) + strlen(path) + 1);
    entry->key[0] = '\0';
    strcat(entry->key, methods[method]);
    strcat(entry->key, path);
    entry->callback = callback;

    HASH_ADD_KEYPTR(hh, meven->method_table, entry->key, strlen(entry->key),
                    entry);
}

// 查找条目
httpCallback meven_getMethod(meven_t *meven, http_header_t *header) {
    method_table_t *entry;
    char *key = malloc(strlen(methods[header->method]) + header->path.len + 1);
    key[0] = '\0';
    strcat(key, methods[header->method]);
    strcat(key, header->path.data);
    HASH_FIND_STR(meven->method_table, key, entry);
    free(key);
    if (entry) {
        return entry->callback;
    } else {
        return NULL;
    }
}

void free_http_header(http_header_t *header) {
    free(header->path.data);
    http_table_t *current_header, *tmp_header;
    HASH_ITER(hh, header->headers, current_header, tmp_header) {
        HASH_DEL(header->headers, current_header);
        free(current_header->key);
        free(current_header->value);
        free(current_header);
    }
}

HTTP_METHOD parse_method(const char *method) {
    for (int i = 0; i < sizeof(methods); i++) {
        if (strcmp(methods[i], method) == 0) {
            return i;
        }
    }
    return -1;
}

http_request_t *parse_request(string request) {
    http_request_t *req = (http_request_t *)malloc(sizeof(http_request_t));
    if (req == NULL) {
        return NULL;
    }
    memset(req, 0, sizeof(http_request_t));
    char *body_cp = strdup(request.data);
    if (!body_cp) {
        return NULL;
    }
    char *body = strstr(request.data, "\r\n\r\n");
    if (body != NULL) {
        *body = '\0';
        body += 4;
        if (*body == '\0') {
            req->body = NULL;
        } else {
            req->body = cJSON_Parse(body);
            if (!req->body) {
                free(body_cp);
                return NULL;
            }
        }
    }
    char *head = strtok(body_cp, "\r\n\r\n");
    char *line = strtok(head, "\r\n");
    if (!line) {
        free(body_cp);
        return NULL;
    }
    // 解析请求行
    char *method_str = strtok(line, " ");
    char *path_str = strtok(NULL, " ");
    char *version_str = strtok(NULL, " ");
    if (!method_str || !path_str || !version_str) {
        free(body_cp);
        return NULL;
    }

    vec_extend(&req->path, &path_str, strlen(path_str));
    // 解析头部字段
    http_header_t *header = &req->header;

    header->method = parse_method(method_str);
    header->path.data = strdup(path_str);
    header->path.len = strlen(path_str);
    strncpy(header->version, version_str, sizeof(header->version) - 1);

    req->method = header->method;

    header->headers = NULL;

    // 解析头部字段
    while ((line = strtok(NULL, "\r\n")) != NULL) {
        if (strcmp(line, "\r\n") == 0) {
            break;
        }
        char *key = strtok(line, ": ");
        char *value = strtok(NULL, "");
        if (!key || !value) {
            free_http_header(header);
            return NULL;
        }
        // 去除 value 前的空格
        while (*value == ' ') {
            value++;
        }
        http_table_t *new_header = malloc(sizeof(http_table_t));
        if (!new_header) {
            free_http_header(header);
            return NULL;
        }
        new_header->key = strdup(key);
        new_header->value = strdup(value);
        HASH_ADD_KEYPTR(hh, header->headers, new_header->key,
                        strlen(new_header->key), new_header);
    }
    free(body_cp);
    return req;
}

char *http_get_header(http_header_t *header, const char *key) {
    http_table_t *entry;
    HASH_FIND_STR(header->headers, key, entry);
    if (entry) {
        return entry->value;
    } else {
        return NULL;
    }
}

void defaultCallback(even_detail *event, char *data, int size) { return; }

void setFdNonBlock(int fd) {
    int opts = fcntl(fd, F_GETFL);
    if (opts < 0) {
        perror("fcntl(F_GETFL)");
        exit(EXIT_FAILURE);
    }
    opts = opts | O_NONBLOCK;
    if (fcntl(fd, F_SETFL, opts) < 0) {
        perror("fcntl(F_SETFL)");
        exit(EXIT_FAILURE);
    }
}

even_detail *meven_even_add(meven_t *meven, uint32_t events, int fd, FD_t type,
                            char *address, int port, long timeout) {
    struct epoll_event *event = malloc(sizeof(struct epoll_event));
    even_detail *e = malloc(sizeof(even_detail));
    e->type = type;
    e->fd = fd;
    e->address = address;
    e->port = port;
    e->timeout = timeout;
    e->is_active = true;
    e->lastActivity = time(NULL);
    event->events = events;
    event->data.ptr = e;
    if (epoll_ctl(meven->epoll_fd, EPOLL_CTL_ADD, fd, event) < 0) {
        perror("epoll_ctl");
        exit(EXIT_FAILURE);
    }
    meven->even_cnt++;
    even_node *node = malloc(sizeof(even_node));
    node->event = event;
    list_add_tail(&node->list, &meven->even_list.list);
    return e;
}

meven_t *meven_init() {
    meven_t *meven = malloc(sizeof(meven_t));
    meven->epoll_fd = epoll_create1(0);
    if (meven->epoll_fd < 0) {
        perror("epoll_create1");
        exit(EXIT_FAILURE);
    }
    meven->even_cnt = 0;
    INIT_LIST_HEAD(&meven->even_list.list);

    vec_init(&default_err_json, 0, 20);
    cJSON *json =
        http_create_response(RESPONSE_BAD_REQUEST, "bad request", NULL);
    char *json_str = cJSON_Print(json);
    vec_extend(&default_err_json, &json_str, strlen(json_str));
    cJSON_Delete(json);
    free(json_str);

    // 初始化callback数组
    for (int i = 0; i < MEVEN_EVENT_CNT; i++) {
        meven->listeners[i] = defaultCallback;
    }
    return meven;
}

inline void meven_setCallback(meven_t *meven, ENUM_EVENT type,
                              evenCallback cb) {
    meven->listeners[type] = cb;
}

void meven_listen(meven_t *meven, int port) {
    // 创建socket 文件
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd < 0) {
        perror("create socket failed");
        exit(EXIT_FAILURE);
    }

    // 设置服务器地址
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    // 设置端口复用
    int optval = 1;
    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

    // 绑定socket 文件到服务器地址
    if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) <
        0) {
        perror("bind addr failed");
        exit(EXIT_FAILURE);
    }

    // 监听socket 文件
    if (listen(listen_fd, 128) < 0) {
        perror("socket listen failed");
        exit(EXIT_FAILURE);
    }

    // 设置socket 文件为非阻塞模式
    setFdNonBlock(listen_fd);
    even_detail *detail =
        meven_even_add(meven, EPOLLIN, listen_fd, FD_LISTEN, NULL, port, -1);
    meven->listeners[EVENT_LISTEN](detail, NULL, 0);
}

void meven_loop(meven_t *meven) {
    int epoll_fd = meven->epoll_fd;
    char buf[1024];
    // 创建epoll 事件数组
    struct epoll_event events[10];
    while (1) {
        int num = epoll_wait(epoll_fd, events, 10, -1);
        if (num < 0) {
            perror("epoll_wait failed");
            exit(EXIT_FAILURE);
        }

        for (int i = 0; i < num; i++) {
            even_detail *detail = (even_detail *)events[i].data.ptr;
            detail->lastActivity = time(NULL);
            if (detail->type == FD_LISTEN) {
                // 处理新连接
                struct sockaddr_in client_addr;
                socklen_t client_addr_len = sizeof(client_addr);
                int client_fd =
                    accept(detail->fd, (struct sockaddr *)&client_addr,
                           &client_addr_len);
                if (client_fd < 0) {
                    perror("accept failed");
                    exit(EXIT_FAILURE);
                }
                setFdNonBlock(client_fd);
                even_detail *ev =
                    meven_even_add(meven, EPOLLIN | EPOLLET, client_fd,
                                   FD_CLIENT, inet_ntoa(client_addr.sin_addr),
                                   ntohs(client_addr.sin_port), -1);
                // 触发accept事件
                printf("accept %s:%d\n", ev->address, ev->port);
                meven->listeners[EVENT_ACCEPT](ev, NULL, 0);
            } else {
                // 处理已连接客户端的数据
                string data;
                vec_init(&data, 0, 256);
                int len;
                while (1) {
                    len = recv(detail->fd, buf, sizeof(buf), 0);
                    if (len < 0) {
                        if (errno == EAGAIN) {
                            // 读取完成
                            break;
                        }
                        // 读取数据失败
                        shutdown(detail->fd, SHUT_RD);
                        detail->is_active = false;
                        meven->listeners[EVENT_ERROR](detail, NULL, 0);
                        goto next;
                    } else if (len == 0) {
                        // 客户端关闭连接, 将客户端监听文件从红黑树中删除
                        shutdown(detail->fd, SHUT_RD);
                        detail->is_active = false;
                        goto next;
                    } else {
                        char *p = buf;
                        vec_extend(&data, &p, len);
                    }
                }
                // 解析请求头
                vec_append(&data, '\0');
                http_request_t *request = parse_request(data);
                httpCallback cb = NULL;
                if (request != NULL) {
                    cb = meven_getMethod(meven, &request->header);
                }
                if (request == NULL || cb == NULL) {
                    meven->listeners[EVENT_DATA](detail, buf, len);
                } else {
                    for (int i = 0; i < meven->routers.len; i++) {
                        // 判断路径前缀是否与路由匹配
                        router_t router = meven->routers.data[i];
                        if (strncmp(request->header.path.data, router.router,
                                    strlen(router.router)) == 0) {
                            // 触发router回调函数
                            router.callback(detail, request);
                        }
                    }
                    // 触发http响应事件
                    cb(detail, request);
                }
                // 清理请求头
                if (request != NULL) {
                    cJSON_Delete(request->body);
                    free_http_header(&request->header);
                    vec_free(&request->path);
                    free(request);
                }
                free(data.data);
            }
        next:
            continue;
        }
        // 清理超时连接
        time_t now = time(NULL);
        even_node *pos, *tmp;
        even_node *head = &meven->even_list;
        list_for_each_entry_safe(pos, tmp, &head->list, list) {
            even_detail *detail = (even_detail *)pos->event->data.ptr;
            if (!detail->is_active ||
                (detail->timeout != -1 &&
                 now - detail->lastActivity > detail->timeout)) {
                // 触发超时事件
                if (detail->is_active) {
                    meven->listeners[EVENT_TIMEOUT](detail, NULL, 0);
                } else {
                    meven->listeners[EVENT_CLOSE](detail, NULL, 0);
                }
                // 删除超时连接
                list_del(&pos->list);
                // 从epoll中删除监听文件
                if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, detail->fd, NULL) < 0) {
                    perror("epoll_ctl failed");
                    exit(EXIT_FAILURE);
                }
                close(detail->fd);
                free(pos);
            }
        }
    }
}

cJSON *http_create_response(RESPONSE_CODE code, char *message, cJSON *data) {
    cJSON *response = cJSON_CreateObject();
    cJSON_AddNumberToObject(response, "code", code);
    cJSON_AddStringToObject(response, "message", message);
    cJSON_AddItemToObject(response, "data", data);
    return response;
}